package com.iustu.agent.dubbo;

import com.iustu.agent.dubbo.model.JsonUtils;
import com.iustu.agent.dubbo.model.Request;
import com.iustu.agent.dubbo.model.RpcInvocation;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class DubboRpcEncoder extends MessageToByteEncoder {
    // header length.
    protected static final int HEADER_LENGTH = 16;
    // magic header.
    protected static final short MAGIC = (short) 0xdabb;
    // message flag.
    protected static final byte FLAG_REQUEST = (byte) 0x80;
    protected static final byte FLAG_TWOWAY = (byte) 0x40;
    protected static final byte FLAG_EVENT = (byte) 0x20;

    @Override
    protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf buffer) throws Exception {
        Request req = (Request) msg;

//        // header.
//        byte[] header = new byte[HEADER_LENGTH];
//        // set magic number.
//        Bytes.short2bytes(MAGIC, header);
//
//        // set request and serialization flag.
//        header[2] = (byte) (FLAG_REQUEST | 6);
//
//        if (req.isTwoWay()) header[2] |= FLAG_TWOWAY;
//        if (req.isEvent()) header[2] |= FLAG_EVENT;
//
//        // set request id.
//        Bytes.long2bytes(req.getId(), header, 4);
//
//        // encode request data.
//        int savedWriteIndex = buffer.writerIndex();
//        buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
//        ByteArrayOutputStream bos = new ByteArrayOutputStream();
//        encodeRequestData(bos, req.getData());
//
//        int len = bos.size();
//        buffer.writeBytes(bos.toByteArray());
//        Bytes.int2bytes(len, header, 12);
//
//        // write
//        buffer.writerIndex(savedWriteIndex);
//        buffer.writeBytes(header); // write header.
//        buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
//    }
//
//    private ByteBuf encode(Request req, ByteBuf buffer) throws Exception {
        byte flag = FLAG_REQUEST | 6;
        if (req.isTwoWay()) {
            flag |= FLAG_TWOWAY;
        }
        if (req.isEvent()) {
            flag |= FLAG_EVENT;
        }

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        encodeRequestData(bos, req.getData());
        int dataLen = bos.size();

        buffer.writeShort(MAGIC)
                .writeByte(flag)
                .writeZero(1)
                .writeLong(req.getId())
                .writeInt(dataLen)
                .writeBytes(bos.toByteArray());
    }

    public void encodeRequestData(OutputStream out, Object data) throws Exception {
        RpcInvocation inv = (RpcInvocation) data;

        PrintWriter writer = new PrintWriter(new OutputStreamWriter(out));

        JsonUtils.writeObject(inv.getAttachment("dubbo", "2.0.1"), writer);
        JsonUtils.writeObject(inv.getAttachment("path"), writer);
        JsonUtils.writeObject(inv.getAttachment("version"), writer);
        JsonUtils.writeObject(inv.getMethodName(), writer);
        JsonUtils.writeObject(inv.getParameterTypes(), writer);

        JsonUtils.writeBytes(inv.getArguments(), writer);
        JsonUtils.writeObject(inv.getAttachments(), writer);
    }

}
